#region Copyright

// The contents of this file are subject to the Mozilla Public License
//  Version 1.1 (the "License"); you may not use this file except in compliance
//  with the License. You may obtain a copy of the License at
//  
//  http://www.mozilla.org/MPL/
//  
//  Software distributed under the License is distributed on an "AS IS"
//  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//  License for the specific language governing rights and limitations under 
//  the License.
//  
//  The Initial Developer of the Original Code is Robert Smyth.
//  Portions created by Robert Smyth are Copyright (C) 2008.
//  
//  All Rights Reserved.

#endregion

using NDependencyInjection;
using NDependencyInjection.interfaces;
using NMock2;
using NMockExtensions;
using NoeticTools.StateEngine.Exceptions;
using NoeticTools.StateEngine.Logging;
using NoeticTools.StateEngine.UATs.Samples.WidgetApp;
using NoeticTools.StateEngine.UATs.Samples.WidgetApp.States;
using NUnit.Framework;
using Assert=NUnit.Framework.Assert;


namespace NoeticTools.StateEngine.UATs.Samples
{
    [TestFixture]
    public class WidgetAppUATs : MockingTestFixture
    {
        private IWidgetListener listener;
        private IStateEngine<IWidget, WidgetState, WidgetStateEvent> stateEngine;
        private Widget widget;

        protected override void SetUp()
        {
            ISystemDefinition systemDefinition = new SystemDefinition();

            systemDefinition.HasInstance(new LogManagerAdapter()).Provides<IContextualLogManager>();

            systemDefinition.HasSingleton<WidgetBusyState>()
                .Provides<WidgetBusyState>();

            systemDefinition.HasSubsystem(
                new StateEngineBuilder<IWidget, WidgetState, WidgetStateEvent>(WidgetState.Idle))
                .Provides<IStateEngine<IWidget, WidgetState, WidgetStateEvent>>();

            stateEngine =
                systemDefinition.Get<IStateEngine<IWidget, WidgetState, WidgetStateEvent>>();

            widget = new Widget(stateEngine);

            listener = NewMock<IWidgetListener>();
        }

        [Test]
        public void CanTransitionOnContextEvent()
        {
            stateEngine.Mapper
                .State(WidgetState.Busy).Uses<WidgetBusyState>()
                .State(WidgetState.Idle).TransitionsTo(WidgetState.Busy).On(WidgetStateEvent.StartOperation);

            Expect.Once.On(listener).Method("Message").With("Entered busy state");

            widget.MoveTo(listener, 42);

            Assert.IsNotNull(stateEngine.CurrentState);
        }

        [Test]
        public void CanTransitionToVirtualStateFromConcreteStateOnStateEvent()
        {
            stateEngine.Mapper
                .State(WidgetState.Busy).Uses<WidgetBusyState>()
                .State(WidgetState.Idle).TransitionsTo(WidgetState.Busy).On(WidgetStateEvent.StartOperation)
                .State(WidgetState.Busy).TransitionsTo(WidgetState.Idle).On(WidgetStateEvent.Suceeded);

            Expect.Once.On(listener).Method("Message").With("Entered busy state");

            var operation = widget.MoveTo(listener, 42);

            operation.SimulateSuccess();
        }

        [Test]
        public void ThrowsExceptionOnSecondContextEventWhenStateDoesNotHaveARuleForTheEvent()
        {
            stateEngine.Mapper
                .State(WidgetState.Busy).Uses<WidgetBusyState>()
                .State(WidgetState.Idle).TransitionsTo(WidgetState.Busy).On(WidgetStateEvent.StartOperation);

            Expect.Once.On(listener).Method("Message").With("Entered busy state");

            widget.MoveTo(listener, 42);
            Assert.Throws<StateEngineEventException>(delegate { widget.MoveTo(listener, 42); });
        }

        [Test]
        public void AllStatesTransition()
        {
            stateEngine.Mapper
                .AllStates().TransitionsTo(WidgetState.Idle).On(WidgetStateEvent.Failed)
                .State(WidgetState.Busy).Uses<WidgetBusyState>()
                .State(WidgetState.Idle).TransitionsTo(WidgetState.Busy).On(WidgetStateEvent.StartOperation);

            Stub.On(listener).Method("Message").With("Entered busy state");

            var operation = widget.MoveTo(listener, 42);

            operation.SimulateFailure();

            Assert.IsNull(stateEngine.CurrentState);
        }
    }
}